package jdec.jdt.ls.decompiler.common;

import java.io.File;

import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Plugin;
import org.eclipse.core.runtime.Status;
import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin;
import org.eclipse.jdt.ls.core.internal.preferences.IPreferencesChangeListener;
import org.eclipse.jdt.ls.core.internal.preferences.PreferenceManager;
import org.eclipse.jdt.ls.core.internal.preferences.Preferences;
import org.osgi.framework.BundleContext;

import jdec.jdt.ls.decompiler.common.source.attach.AttachSourceHandler;
import jdec.jdt.ls.decompiler.common.util.Logger;
import static org.eclipse.jdt.ls.core.internal.handlers.MapFlattener.getValue;


public class JavaDecompilerPlugin extends Plugin implements IPreferencesChangeListener {

    private static final String JDT_PLUGIN = "jdec.jdt.ls.decompiler";
    static final String CACHE_KEY = "java.decompiler.cache";

    private static String TEMP_DIR = null;

    private static JavaDecompilerPlugin pluginInstance;
    private static BundleContext context;
    private volatile Preferences preferences;
    private volatile boolean enableCache;


    public static JavaDecompilerPlugin getDefault() {
        return pluginInstance;
    }

    @Override
    public void start(BundleContext context) throws Exception {
        super.start(context);
        JavaDecompilerPlugin.context = context;
        JavaDecompilerPlugin.pluginInstance = this;

        initPreferences();

        TEMP_DIR = System.getProperty("java.io.tmpdir") + File.separator + "." + JDT_PLUGIN + System.currentTimeMillis();
    }

    private void initPreferences() {
        PreferenceManager preferencesManager = JavaLanguageServerPlugin.getPreferencesManager();
        preferencesManager.addPreferencesChangeListener(this);
        // default
        preferences = preferencesManager.getPreferences();
        Object java_decompiler_cache = getValue(preferences.asMap(), CACHE_KEY);
        if (java_decompiler_cache != null) {
            enableCache = Boolean.valueOf(java_decompiler_cache.toString());
        }
    }

    @Override
    public void stop(BundleContext context) throws Exception {
        JavaDecompilerPlugin.context = null;
        JavaDecompilerPlugin.pluginInstance = null;

        PreferenceManager preferencesManager = JavaLanguageServerPlugin.getPreferencesManager();
        if (preferencesManager != null) preferencesManager.removePreferencesChangeListener(this);
    }

    public static String tempDir() {
        if (!new File(TEMP_DIR).exists()) {
            new File(TEMP_DIR).mkdirs();
        }
        return TEMP_DIR;
    }

    public static void logError(Throwable t, String message) {
        JavaDecompilerPlugin.getDefault()
                .getLog()
                .log(new Status(IStatus.ERROR, JDT_PLUGIN, 0, message, t));
    }

    public static void logInfo(String message) {
        JavaDecompilerPlugin.getDefault()
                .getLog()
                .log(new Status(IStatus.INFO, JDT_PLUGIN, 0, message, null));
    }

    public static void log(int severity, Throwable t, String message) {
        JavaDecompilerPlugin.getDefault()
                .getLog()
                .log(new Status(severity, JDT_PLUGIN, 0, message, t));
    }

    public boolean probeAttachSource(IPackageFragmentRoot packageFragmentRoot) {
        try {
            if (packageFragmentRoot.getPath() != null && packageFragmentRoot.getSourceAttachmentPath() == null) {
                return new AttachSourceHandler().syncAttachSource(packageFragmentRoot);
            }
        } catch (JavaModelException e) {
            Logger.debug(e);
        }
        return false;
    }

    public boolean probeAttachSource(IClassFile classFile) {
        return new AttachSourceHandler().syncAttachSource(classFile);
    }

    public String getExportEncoding() {
        return "utf-8";
    }

    @Override
    public void preferencesChange(Preferences oldPreferences, Preferences newPreferences) {
        this.preferences = newPreferences;
        initPreferences();
    }

    /**
     * @return the preferences
     */
    public Preferences getPreferences() {
        return preferences;
    }

    public boolean isEnableCache() {
        return enableCache;
    }
}
